/*
 * =====================================================================================
 *
 *       Filename:  echo_process_tcp_svr.cpp
 *
 *    Description:  简单的tcp echo服务器，对于每个连接启动一个进程来处理
 *
 *        Version:  1.0
 *        Created:  2008年09月01日 14时12分08秒
 *       Revision:  none
 *       Compiler:  g++
 *
 *         Author:  ZhixiongHong (hzx), fishwarter@gmail.com
 *        Company:  Unioncast
 *
 * =====================================================================================
 */

#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>


#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <iostream>



using namespace std;

#define SERV_PORT		9800
#define LISTENQ			16
#define MAX_LINE		2048

void str_echo(int sockfd);

void sig_chld(int signo)
{
	pid_t		pid;
	int			stat;
	while( (pid = waitpid(-1, &stat, WNOHANG))> 0)
		printf("child %d terminated\n", pid);

	return ;
}

int main(int argc, char** argv)
{
	signal(SIGCHLD, sig_chld);
	signal(SIGPIPE, SIG_IGN);

	pid_t		childpid;
	int 		listenfd, connfd;
	socklen_t	clilen;
	struct		sockaddr_in	cliaddr, servaddr;

	listenfd = socket(AF_INET, SOCK_STREAM,0);	
	if(listenfd < 0)
	{
		cout << "create listenfd error " << strerror(errno) << endl;
		return -1;
	}

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(SERV_PORT);
	
	const int on = 1;
	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	int retint = bind(listenfd, (sockaddr *)&servaddr, sizeof(servaddr));
	if( retint)
	{
		cout << "bind listenfd error: "  << strerror(errno) << endl;
		return -1;
	}
	
	retint = listen(listenfd, LISTENQ);
	if( retint)
	{
		cout << "listen error " << strerror(errno) << endl;
		return -1;
	}
	
	cout << "start svr at " << SERV_PORT << endl;
	for(; ;)
	{
		clilen = sizeof(cliaddr);
		connfd = accept(listenfd, (sockaddr *)&cliaddr, &clilen);
		cout << "accept new connection......." << endl;
		if( connfd > 0 )
		{
			if( (childpid = fork()) == 0) 
			{
				close(listenfd);
				str_echo(connfd);
				exit(0);
			}
			cout << "close conn socket " << endl;
			close(connfd);
		}
	}
	return 0;
}

void  str_echo(int sockfd)
{
	cout << "str_echo ..... " << endl;
	ssize_t 	n = 0;
	char 		buf[MAX_LINE];

again:
//	while( ( n = read(sockfd, buf, MAX_LINE)) > 0 )	
	n = read(sockfd, buf, MAX_LINE);
	{
		cout << "get " << buf << " len = " << n << " strlen(buf)= " << strlen(buf) << endl;
		write(sockfd, buf, strlen(buf));
	}
	if( n < 0 && errno == EINTR)
	{
		cout << "try again " << endl;
		goto again;
	}
	else if( n < 0 )
		cout << "str_echo: read error " << endl;
}


